/*
 * Author: 王迪 1300012802
 *
 * Outline:
 * 基本与main_new类似。
 *
 * Optimization:
 * 利用了数据中评论的编号是连续的10的倍数的特点，进行了一些常数优化。
 *
 * Performance:
 * 10k的数据需要2.5s，其中大部分时间在IO及数据的处理上。
 */
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <functional>
#include <algorithm>

#include <fast_reader.hpp>

using namespace std;

FastReader reader;

unordered_map<int, int> person_id_to_axis;
vector<int> person_axis_to_id;

vector<int> comment_axis_to_person_axis;

vector<unordered_map<int, int>> person_axis_to_comment_cnt_on_relation;

vector<vector<pair<int, int>>> person_axis_to_persons;

void handlePerson(int person_cnt, const string &data_path)
{
    string person_data_file = data_path + "person.csv";
    reader.fastOpen(person_data_file.c_str());
    int axis_index = 0;
    
    person_id_to_axis.clear();
    person_axis_to_id.resize(person_cnt);
    reader.skipLine();
    while (reader.hasNext())
    {
        int person_id = reader.getInt();
        reader.skipLine();

        person_id_to_axis[person_id] = axis_index;
        person_axis_to_id[axis_index] = person_id;

        ++ axis_index;
    }

    reader.fastClose();
}

void handleCommentHasCreator(const string &data_path)
{
    string comment_has_creator_data_file = data_path + "comment_hasCreator_person.csv";
    reader.fastOpen(comment_has_creator_data_file.c_str());

    comment_axis_to_person_axis.clear();
    reader.skipLine();
    while (reader.hasNext())
    {
        int comment_id = reader.getInt();
        int person_id = reader.getInt();
        reader.skipLine();

        int person_axis = person_id_to_axis[person_id];

        comment_axis_to_person_axis.push_back(person_axis);
    }

    reader.fastClose();
}

void handleCommentReplyOfComment(int person_cnt, const string &data_path)
{
    string comment_reply_of_comment_data_file = data_path + "comment_replyOf_comment.csv";
    reader.fastOpen(comment_reply_of_comment_data_file.c_str());

    vector<pair<int, int>> comments, temp;

    person_axis_to_comment_cnt_on_relation.clear();
    person_axis_to_comment_cnt_on_relation.resize(person_cnt);
    reader.skipLine();
    while (reader.hasNext())
    {
        int comment_origin_id = reader.getInt();
        int comment_reply_id = reader.getInt();
        reader.skipLine();

        int comment_origin_person_axis = comment_axis_to_person_axis[comment_origin_id / 10];
        int comment_reply_person_axis = comment_axis_to_person_axis[comment_reply_id / 10];

        comments.push_back(make_pair(comment_origin_person_axis, comment_reply_person_axis));
    }

    reader.fastClose();

    int comment_cnt = comments.size();
    temp.resize(comments.size());
    
    int *memo = new int[person_cnt + 1];
    int *cnt = memo + 1;
    memset(memo, 0, sizeof(int) * (person_cnt + 1));
    for (const auto &p : comments)
        ++ cnt[p.second];
    for (int i = 0; i < person_cnt; ++ i)
        cnt[i] += cnt[i - 1];
    for (int i = comment_cnt - 1; i >= 0; -- i)
        temp[-- cnt[comments[i].second]] = comments[i];
    comments.swap(temp);
    memset(memo, 0, sizeof(int) * (person_cnt + 1));
    for (const auto &p : comments)
        ++ cnt[p.first];
    for (int i = 0; i < person_cnt; ++ i)
        cnt[i] += cnt[i - 1];
    for (int i = comment_cnt - 1; i >= 0; -- i)
        temp[-- cnt[comments[i].first]] = comments[i];
    comments.swap(temp);
    delete [] memo;

    for (int i = 0, j = 0; i < comment_cnt; i = j) 
    {
        while (j < comment_cnt && comments[j] == comments[i])
            ++ j;
        person_axis_to_comment_cnt_on_relation[comments[i].first][comments[i].second] = j - i;
    }
}

void handlePersonKnowsPerson(int person_cnt, const string &data_path)
{
    string person_knows_person_data_file = data_path + "person_knows_person.csv";
    reader.fastOpen(person_knows_person_data_file.c_str());

    person_axis_to_persons.clear();
    person_axis_to_persons.resize(person_cnt);
    reader.skipLine();
    while (reader.hasNext())
    {
        int person_from_id = reader.getInt();
        int person_to_id = reader.getInt();
        reader.skipLine();

        int person_from_axis = person_id_to_axis[person_from_id];
        int person_to_axis = person_id_to_axis[person_to_id];

        int comment_cnt = 0;
        unordered_map<int, int> &comment_cnt_on_relation = person_axis_to_comment_cnt_on_relation[person_from_axis];
        if (comment_cnt_on_relation.count(person_to_axis))
            comment_cnt = comment_cnt_on_relation[person_to_axis];
        if (comment_cnt > 0)
        {
            unordered_map<int, int> &comment_cnt_on_relation = person_axis_to_comment_cnt_on_relation[person_to_axis];
            if (comment_cnt_on_relation.count(person_from_axis))
                comment_cnt = min(comment_cnt, comment_cnt_on_relation[person_from_axis]);
            else
                comment_cnt = 0;
        }

        person_axis_to_persons[person_from_axis].push_back(make_pair(person_to_axis, comment_cnt));
    }
    
    reader.fastClose();

    for (int p = 0; p < person_cnt; ++ p) 
    {
        vector<pair<int, int>> &to_persons = person_axis_to_persons[p];
        sort(begin(to_persons), end(to_persons), [](const pair<int, int> &a, const pair<int, int> &b){ return a.second > b.second; });
    }
}


int *q, *dist, *dfn;
bool *flag;
int timestamp;

int calculateShortestPath(int person_from, int person_to, int bound)
{
    if (person_from == person_to)
        return 0;

    int qh = 0, qt = 0;
    ++ timestamp;

    dist[person_from] = dist[person_to] = 0;
    dfn[person_from] = dfn[person_to] = timestamp;
    flag[person_from] = 0;
    flag[person_to] = 1;
    q[qt ++] = person_from;
    q[qt ++] = person_to;
    
    while (qh != qt)
    {
        int u = q[qh ++];
        vector<pair<int, int>> &to_persons = person_axis_to_persons[u];
        for (const auto &p : to_persons)
        {
            if (p.second < bound)
                break;

            int v = p.first;
            if (dfn[v] == timestamp && flag[u] != flag[v])
                return dist[u] + dist[v] + 1;
            else
            {
                if (dfn[v] < timestamp)
                {
                    dist[v] = dist[u] + 1;
                    dfn[v] = timestamp;
                    flag[v] = flag[u];
                    q[qt ++] = v;
                }
            }
        }
    }

    return -1;
}

int main(int argc, char *argv[])
{
#ifndef LOCAL
    string data_path(argv[1]);
    int person_cnt = atoi(argv[2]);
    string query_file(argv[3]);
    string answer_file(argv[4]);
#else
    string data_path("../../../data/10k-network/");
    int person_cnt = 10000;
    string query_file("../query1.in");
    string answer_file("../query1.out");
#endif

    handlePerson(person_cnt, data_path);
    handleCommentHasCreator(data_path); 
    handleCommentReplyOfComment(person_cnt, data_path); 
    handlePersonKnowsPerson(person_cnt, data_path);

    FILE *f_query = fopen(query_file.c_str(), "r");
    FILE *f_answer = fopen(answer_file.c_str(), "w");

    int person_from_id, person_to_id, comment_cnt_lower_bound;

    q = new int[person_cnt];
    dist = new int[person_cnt];
    dfn = new int[person_cnt];
    flag = new bool[person_cnt];
    timestamp = 0;
    memset(dfn, 0, sizeof(int) * person_cnt);

    while (fscanf(f_query, "%d%d%d", &person_from_id, &person_to_id, &comment_cnt_lower_bound) != EOF)
    {
        int person_from_axis = person_id_to_axis[person_from_id];
        int person_to_axis = person_id_to_axis[person_to_id];
        ++ comment_cnt_lower_bound;
        
        fprintf(f_answer, "%d\n", calculateShortestPath(person_from_axis, person_to_axis, comment_cnt_lower_bound));
    }

    fclose(f_query);
    fclose(f_answer);

    delete [] q;
    delete [] dist;
    delete [] dfn;
    delete [] flag;

    return 0;
}
